#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main() {

  //无类型指针
  int x = 10;
  //整数指针转化为 void 指针
  void* p = &x;
  // void指针转化为整数
  int* q = p;
  char a = 'x';
  void* p1 = &a;
  // void 指针,无法取出指针指向的值
  // printf("%c\n", *p1);
  // malloc 为任意类型的数据分配内存
  int* p2 = malloc(sizeof(int));
  *p2 = 12;
  printf("%d\n", *p2);
  // 等同
  int* p3 = (int *) malloc(sizeof(int));
  // 分配失败返回 Null
  if (p3 == NULL) {
    //
  }
  if (!p3) {
    //
  }
  // 为数组和自定义数据结构分配内存
  // p4是一个可以放置10个整数的内存
  int* p4 = (int *) malloc(sizeof(int) * 10);
  for(int i=0;i<10;i++) {
    p4[i] = i*5;
  }
  // malloc 不会自动初始化内存,如果不手动修改会访问到这段内存以前的值
  int* p5 = malloc(4);
  // 手动修改
  // strcpy(p5, 'abc');
  // 或者
  // p5 = 'abc1';
  // 也可以全部初始化为0
  memset(p5, 0, sizeof(int)*5);
  
  // 释放内存
  free(p5);

  // calloc 将所有的值初始化为0
  int* p6 = calloc(10, sizeof(int));
  // 也需要 free释放内存
  free(p6);
  // realloc 修改内存快的大小,成功返回一个新的,失败也返回一个 Null
  int* newp6 = realloc(p6, sizeof(int) *100);
  // 第一个参数可以传 Null,这样视为创建一个新的内存快
  int* p7 = realloc(NULL, sizeof(int)*100);
  // realloc 也不会对内存初始化
  // 但是有可能返回一个新的地址或者返回一个和原来一样的地址
  // 优先在原来的基础上修改
  int* b;
  // 手动动态调整内存
  b = malloc(sizeof(int) * 10);
  b = realloc(b, sizeof(int) * 2000);
  // 受限指针
  // 意思就是该内存只能让这个指针访问
  int* restrict p8;
  p8 = malloc(sizeof(int));
  // 不能有另外一个指针去指向这个
  // 用一块内存拷贝到另一块内存
  char s[] = "Goast!";
  char t[100];
  memcpy(t, s, sizeof(s)); // 拷贝7个字节包括终止符
  printf("%s\n", t);
  // 比strcpy()更好更快
  // memmove 允许目标和原来的重叠
  int a1[100];
  // 从a1[1]开始,都向后移动一个位置
  memmove(&a1[0], &a1[1], 99 * sizeof(int));
  char x1[] = "Home Sweet Home";
  // 输出 Sweet Home Home
  printf("%s\n", (char *) memmove(x1, &x1[5], 10));
  // memcmp()函数用来比较两个内存区域 相同就返回0
  char* s11 = "abc";
  char* s12 = "acd";
  int r = memcmp(s11, s12, 3); // 小于 0

  char s21[] = {'b', 'i', 'g', '\0', 'c', 'a', 'r'};
  char s22[] = {'b', 'i', 'g', '\0', 'c', 'a', 't'};

  if (memcmp(s21, s22, 3) == 0) // true
  if (memcmp(s21, s22, 4) == 0) // true
  if (memcmp(s21, s22, 7) == 0) // false

  return 0;
}  